#!/bin/bash

work_dir=""
name="rs_u20_ros_docker"
docker_image="rs:u20-ros"
container_env="${name}_env"
docker_home="/home/ht"
docker_password="ht"

error() {
    local date=$(date)
    local para=$1
    echo -e "\033[31m[$date] error : $para \033[0m"
}

info() {
    local date=$(date)
    local para=$1
    echo -e "\033[32m[$date] info : $para \033[0m"
}

fun_do_help() {
    echo "usage: $0 [-r / --run] [-s / --stop] [-e / --exce] [-k / --kill <name>] [--remove]"
    echo "  [-r / --run] 运行容器，支持容器其他的运行参数,使用++替代--"
    echo "  [-s / --stop] 停止容器，支持传入容器的名称，默认名称 : $name"
    echo "  [-e / --exce] 进入容器，支持传入容器的名称，默认名称 : $name"
    echo "  [-k / --kill] 杀死容器，支持传入容器的名称，默认名称 : $name"
    echo "  [--remove] 删除容器，支持传入容器的名称，默认名称 : $name"
    echo "  eg:"
    echo "      $0"
    echo "      $0 -r"
    echo "      $0 --run"
    echo "      $0 -r +[容器参数] ++[容器参数]=xxx"
    echo "      $0 -e"
    echo "      $0 -exce"
    echo "      $0 -s"
    echo "      $0 -stop"
    echo "      $0 -k"
    echo "      $0 --kill"
    echo "      $0 --remove"
}

fun_gen_install_run() {

    # 如果自动启动脚本不存在，则生成
    if [[ -f "$work_dir/$container_env/auto_scripts/auto_install.sh" ]]; then
        return
    fi

    # 生成安装脚本
    cat <<EOF >"$work_dir/$container_env/auto_scripts/auto_install.sh"
#!/bin/bash

password="$docker_password"

run_packages_path=\$HOME/package
run_package_install_iofo=\$HOME/.run_package_install_iofo

# 如果\$run_package_install_iofo文件不存在，则创建该文件
if [[ ! -f "\$run_package_install_iofo" ]]; then
    touch \$run_package_install_iofo
fi

# 通过find命令，查找\${run_packages_path}目录下的所有.run文件
run_files=\$(find \${run_packages_path} -name "*.run")

# 通过find命令，查找\${run_packages_path}目录下的所有.deb文件
deb_files=\$(find \${run_packages_path} -name "*.deb")

# 遍历文件，并校验md5值，如果md5值与已安装的文件不一致，则执行安装
for file in \$run_files; do

    # 判断文件是否有执行权限，如果没有，则赋予执行权限
    if [[ ! -x "\$file" ]]; then
        chmod +x "\$file"
    fi

    # 获取文件名
    filename=\$(basename -- "\$file")
    # 获取文件的md5值
    md5=\$(md5sum "\$file" | awk '{print \$1}')
    # 判断是否已经安装该run文件
    is_installed=\$(cat \$run_package_install_iofo | grep "\$filename")
    # 如果没有安装，则执行安装
    if [[ -z "\$is_installed" ]]; then
        echo "install \${filename} ..."
        echo "\$password" | sudo -S "\${file}"
        # 安装完成后，记录已安装的文件的md5值
        echo "\$filename \$md5" >>\$run_package_install_iofo
        continue
    fi

    # 获取已安装的文件的md5值
    installed_md5=\$(cat \$run_package_install_iofo | grep "\$filename" | awk '{print \$2}')
    # 如果md5值不一致，则执行安装
    if [[ "\$md5" != "\$installed_md5" ]]; then
        echo "install \${filename} ..."
        echo "\$password" | sudo -S "\${file}"
        # 安装完成后，更新已安装的文件的md5值
        sed -i "s/\$filename.*/\$filename \$md5/g" \$run_package_install_iofo
    fi
done

# 遍历文件，并校验md5值，如果md5值与已安装的文件不一致，则执行安装
for file in \$deb_files; do

    # 判断文件是否有执行权限，如果没有，则赋予执行权限
    if [[ ! -x "\$file" ]]; then
        chmod +x "\$file"
    fi

    # 获取文件名
    filename=\$(basename -- "\$file")
    # 获取文件的md5值
    md5=\$(md5sum "\$file" | awk '{print \$1}')
    # 判断是否已经安装该run文件
    is_installed=\$(cat \$run_package_install_iofo | grep "\$filename")
    # 如果没有安装，则执行安装
    if [[ -z "\$is_installed" ]]; then
        echo "install \${filename} ..."
        echo "\$password" | sudo -S dpkg -i "\${file}"
        # 安装完成后，记录已安装的文件的md5值
        echo "\$filename \$md5" >>\$run_package_install_iofo
        continue
    fi

    # 获取已安装的文件的md5值
    installed_md5=\$(cat \$run_package_install_iofo | grep "\$filename" | awk '{print \$2}')
    # 如果md5值不一致，则执行安装
    if [[ "\$md5" != "\$installed_md5" ]]; then
        echo "install \${filename} ..."
        echo "\$password" | sudo -S dpkg -i "\${file}"
        # 安装完成后，更新已安装的文件的md5值
        sed -i "s/\$filename.*/\$filename \$md5/g" \$run_package_install_iofo
    fi
done

EOF

    # 赋予脚本可执行权限
    chmod +x "$work_dir/$container_env/auto_scripts/auto_install.sh"
}

fun_gen_docker_rs_auto_start() {

    # 如果自动启动脚本不存在，则生成
    if [[ -f "$work_dir/$container_env/auto_scripts/rs_auto_start.sh" ]]; then
        return
    fi

    # 生成自动启动脚本
    cat <<EOF >"$work_dir/$container_env/auto_scripts/rs_auto_start.sh"
#!/bin/bash

# 运行安装脚本
\$HOME/auto_scripts/auto_install.sh

# 运行自启动脚本
\$HOME/auto_scripts/auto_start.sh

# 执行完脚本后，将当前终端的shell切换为zsh，不然无法启动docker
/bin/zsh

EOF

    # 赋予脚本可执行权限
    chmod +x "$work_dir/$container_env/auto_scripts/rs_auto_start.sh"
}

fun_gen_auto_start() {

    # 如果自动启动脚本不存在，则生成
    if [[ -f "$work_dir/$container_env/auto_scripts/auto_start.sh" ]]; then
        return
    fi

    # 生成自动启动脚本
    cat <<EOF >"$work_dir/$container_env/auto_scripts/auto_start.sh"
#!/bin/bash

password="$docker_password"

# 加载依赖库
echo "\$password" | sudo -S ldconfig

# 1. 定义一个字典，用于存储有数字序号的文件路径列表
declare -A numbered_files_dict

# 2. 定义一个字典，用于存储普通无数字序号的文件路径列表
declare -A no_number_files_dict

# 3. 定义自启动路径的变量
auto_start_path=\$HOME/AutoStart

# 4. 获取\${auto_start_path}目录下的所有.sh/.py文件
files=\$(ls \${auto_start_path}/*.sh \${auto_start_path}/*.py 2>/dev/null)

# 5. 遍历文件，提取文件名中的数字编号，数字编号格式 xxx_01.sh
for file in \${files}; do
    number=\$(basename -- "\$file" | sed 's/[^0-9]*//g')
    if [[ -n \$number ]]; then
        # 如果数字已经存在于字典中，则将文件路径添加到列表中
        if [[ \${numbered_files_dict[\${number}]+_} ]]; then
            numbered_files_dict[\${number}]="\${numbered_files_dict[\${number}]} \$file"
        else
            numbered_files_dict[\${number}]=\$file
        fi
    else
        # 如果文件名中没有数字，则将文件路径存储在 no_num 键下
        filename=\$(basename -- "\$file")
        no_number_files_dict["no_num_\$filename"]=\$file
    fi
done

# 6. 获取字典 numbered_files_dict 的所有key，并对key进行数字排序，有数字在最前面，无数字的key在最后面
numbered_keys=(\$(echo "\${!numbered_files_dict[@]}" | tr ' ' '\n' | sort -n))

# 7. 遍历有数字序号的文件列表并依次启动
for key in \${numbered_keys[@]}; do
    file_path=\${numbered_files_dict[\$key]}
    # 如果文件列表不为空，则按顺序启动文件
    if [[ \$file_path =~ " " ]]; then

        echo "Starting \${key} files..."
        for file in \${file_path}; do
            
            # 判断文件是否有执行权限，如果没有，则赋予执行权限
            if [[ ! -x "\$file" ]]; then
                chmod +x "\$file"
            fi

            echo "Starting \${file}..."
            \${file}
        done
    else
        echo "Starting \${file_path}..."
        # 判断文件是否有执行权限，如果没有，则赋予执行权限
        if [[ ! -x "\$file_path" ]]; then
            chmod +x "\$file_path"
        fi
        \${file_path}
    fi
done

# 8. 获取字典 no_number_files_dict 的所有key，并对key进行排序
# no_number_keys=(\$(echo "\${!no_number_files_dict[@]}" | tr ' ' '\n' | sort))

# 9. 遍历普通无数字序号的文件列表并依次启动
# for key in \${no_number_keys[@]}; do
#     file_path=\${no_number_files_dict[\$key]}
#
#    # 判断文件是否有执行权限，如果没有，则赋予执行权限
#    if [[ ! -x "\$file_path" ]]; then
#        chmod +x "\$file_path"
#    fi
#    
#     echo "Starting \${file_path}..."
#     \${file_path}
# done

echo "All auto start files have been started ..."

EOF

    # 赋予可执行权限
    chmod +x "$work_dir/$container_env/auto_scripts/auto_start.sh"

}

fun_do_config() {
    work_dir="$HOME"

    # 获取脚本所在目录
    # current_dir=$(
    #     cd "$(dirname "$0")"
    #     pwd
    # )

    mkdir -p $work_dir/$container_env/AutoStart
    mkdir -p $work_dir/$container_env/auto_scripts
    mkdir -p $work_dir/$container_env/scripts
    mkdir -p $work_dir/$container_env/package
    mkdir -p $work_dir/$container_env/welog
    mkdir -p $work_dir/$container_env/roadside
    mkdir -p $work_dir/$container_env/roadside_app
    mkdir -p $work_dir/$container_env/roadside_qt/config

    fun_gen_install_run
    fun_gen_auto_start
    fun_gen_docker_rs_auto_start

    # 将脚本拷贝到工作目录
    # cp -rf $current_dir/* $work_dir/$container_env/scripts/.

    echo "config dir: $work_dir/$container_env"
}

fun_do_run() {
    # 允许本地访问xhost +
    xhost +

    shift 2 # 除去前两个变量 -r --
    docker_run_arg=" "
    if [ " $@" != " " ]; then
        docker_run_arg=$(echo $@ | sed 's/+/-/g')
    fi

    ret="$(docker ps -a | grep "$name")"
    if [ " $ret" == " " ]; then
        info "start run [$name] docker container"
        fun_do_config

        docker run -it \
            --privileged \
            --net=host \
            --ipc=host \
            --pid=host \
            --name=$name \
            -e DISPLAY=$DISPLAY \
            -v /tmp/.X11-unix:/tmp/.X11-unix \
            -v /run/dbus/system_bus_socket:/run/dbus/system_bus_socket:ro \
            -v $work_dir/$container_env/scripts:$docker_home/scripts \
            -v $work_dir/$container_env/AutoStart:$docker_home/AutoStart \
            -v $work_dir/$container_env/auto_scripts/auto_start.sh:$docker_home/auto_scripts/auto_start.sh \
            -v $work_dir/$container_env/auto_scripts/auto_install.sh:$docker_home/auto_scripts/auto_install.sh \
            -v $work_dir/$container_env/auto_scripts/rs_auto_start.sh:$docker_home/auto_scripts/rs_auto_start.sh \
            -v $work_dir/$container_env/package:$docker_home/package \
            -v ~/Documents:$docker_home/workspace \
            -v $work_dir/$container_env/welog:$docker_home/.welog \
            -v $work_dir/$container_env/roadside:$docker_home/.roadside \
            -v $work_dir/$container_env/roadside_qt:$docker_home/.roadside_qt \
            -v $work_dir/$container_env/roadside_app:$docker_home/.roadside_app \
            $docker_run_arg \
            -d $docker_image \
            /bin/bash $docker_home/auto_scripts/rs_auto_start.sh

    else
        info "start run [$name] docker container"
        docker start $name
    fi
}

fun_do_kill() {
    shift 2 # 除去前两个变量 -r --
    kill_name=$name
    if [ " $@" != " " ]; then
        kill_name=$@
    fi

    ret="$(docker ps -a | grep "$kill_name")"
    if [ " $ret" == " " ]; then
        error "can not find [$kill_name] docker container"
        exit -1
    fi

    info "kill [$kill_name] docker container"
    docker kill $kill_name
}

fun_do_exec() {
    shift 2 # 除去前两个变量 -r --
    exec_name=$name
    if [ " $@" != " " ]; then
        exec_name=$@
    fi

    ret="$(docker ps -a | grep "$exec_name")"
    if [ " $ret" == " " ]; then
        fun_do_run
    fi

    info "exec [$exec_name] docker container"
    docker exec -it $exec_name /bin/zsh
    # CPID=$(docker inspect --format "{{.State.Pid}}" $CNAME)
    # nsenter --target "$CPID" --mount --uts --ipc --net --pid
}

fun_do_remove() {
    shift 2 # 除去前两个变量 -r --
    remove_name=$name
    if [ " $@" != " " ]; then
        remove_name=$@
    fi

    ret="$(docker ps -a | grep "$remove_name")"
    if [ " $ret" == " " ]; then
        error "can not find $remove_name docker container"
        exit -1
    fi

    info "remove [$remove_name] docker container"
    docker rm $remove_name
}

fun_do_stop() {
    shift 2 # 除去前两个变量 -r --
    stop_name=$name
    if [ " $@" != " " ]; then
        stop_name=$@
    fi

    ret="$(docker ps -a | grep "$stop_name")"
    if [ " $ret" == " " ]; then
        error "can not find $stop_name docker container"
        exit -1
    fi

    info "stop [$stop_name] docker container"
    docker stop $stop_name
}

fun_do_restart() {
    shift 2 # 除去前两个变量 -r --
    restart_name=$name
    if [ " $@" != " " ]; then
        restart_name=$@
    fi

    ret="$(docker ps -a | grep "$restart_name")"
    if [ " $ret" == " " ]; then
        error "can not find $restart_name docker container"
        exit -1
    fi

    info "restart [$restart_name] docker container"
    docker restart $restart_name
}

main() {
    ARGS=$(getopt -o h,r::,k::,e::,s:: --long help,run::,kill::,exec::,stop::,restart,remove:: -- "$@")
    if [ $? != 0 ]; then
        echo "Terminating..." >&2
        exit 1
    fi
    eval set -- "$ARGS"

    while true; do
        case "$1" in
        -h | --help)
            fun_do_help
            exit 0
            ;;
        -r | --run)
            fun_do_run $@
            exit 0
            ;;
        -k | --kill)
            fun_do_kill $@
            exit 0
            ;;
        -s | --stop)
            fun_do_stop $@
            exit 0
            ;;
        -e | --exec)
            fun_do_exec $@
            exit 0
            ;;
        --remove)
            fun_do_stop $@
            fun_do_remove $@
            exit 0
            ;;
        --restart)
            fun_do_restart $@
            exit 0
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "unknow : {$1}"
            exit 1
            ;;
        esac
    done

}

main "$@"
